import { volatileRoutes } from '@/router/routes'
import Layout from '@/layout'
import Nested from '@/layout/nested/index'
import Page404 from '@/views/404'
import Iframe from '@/layout/iframe'

import { isExternal } from './validate'

class RouterModel {
  constructor(path, component, mate, code) {
    this.path = path
    this.component = component
    this.meta = mate
    this.name = code // 用到快捷导航栏 tagsView 时必须开起
    this.cname = code // 这里实际存的是router 的name，为了避免name值重复，浏览器报出警告，改名为cname
  }
}

class Meta {
  constructor(title, icon) {
    this.title = title
    this.icon = icon
  }
  msgNum
}
// 用来装所有的 内部路由的 path，防止path的重复
const interiorPath = new Set()
// 组件上的按钮权限，name:[permission]
const buttonPermission = new Map()
// path 和 name  对应的一个map
// const pathNameMap = new Map()
/**
 *  根据后台传入的name值查找原始路由，在name值查找不到的时候会根据path去查
 *  对外暴露的，构建路由工具类的方法
 *
 *  step one 第一步 构建最外层路由
 */
const buildRouters = function(menus) {
  // 定义路由
  const routers = []
  if (!!menus && menus.length > 0) {
    menus.forEach((menu) => {
      let routerModel
      // 构建第一级路由
      // 有下级
      if (!!menu && !!menu.children && menu.children.length > 0 && (!menu.menuType || menu.menuType < 4)) {
        // 组织的是菜单项，不能直接链接，只能打开下级
        routerModel = new RouterModel(buildPahtUrl(menu.id, menu.path), Layout, new Meta(menu.title, buildIcon(menu.icon)))
        // 构建子路由
        routerModel.children = []
        buildChildRouter(menu.children, routerModel)
        // 如果有下级 ，把上级的跳转，指下子集的第一个
        if (routerModel.children && routerModel.children.length > 0) {
          routerModel.redirect = routerModel.children[0].path
        }
      } else if (menu && menu.isOutside) { // 没有下级 而且是外链
        // 组装的是外链
        // routerModel = new RouterModel(buildPahtUrl(menu.id, menu.path), Layout, new Meta(menu.title, buildIcon(menu.icon)))
        routerModel = buildLinkRouterModel(menu)
      } else if (!menu.menuType || menu.menuType < 4) { // 没有下级，而且是内部路由 ,且不是按钮
        const path = buildPahtUrl(menu.id, menu.path)
        const routerModel1 = findOrgRouter(menu, volatileRoutes)
        const children = []
        children.push(routerModel1)
        routerModel = {
          path: path,
          component: Layout,
          redirect: routerModel1.path,
          children: children
        }
      }
      routers.push(routerModel)
    })
  }
  // 如果路由中没有index 页面
  if (!interiorPath.has('/') && routers.length > 0) {
    routers[0].path = '/'
  }
  // 返回的是路由加按钮权限的对象
  return {
    routers,
    buttonPermission // 按钮权限
  }
}

/**
 * 构建子路由
 * @param menus
 * @param routerModel
 *
 * step two 第二步 构建子路由
 */
function buildChildRouter(menus, routerModel) {
  // console.log('==voRoutes==',voRoutes)
  if (!!menus && menus.length > 0) {
    menus.forEach((menu) => {
      if (!menu.menuType || menu.menuType < 4) { // 判断如果不是按钮类型的
        const router = findOrgRouter(menu, volatileRoutes)
        if (!!menu.children && menu.children.length > 0) { // 如果还有下级
          router.children = []
          buildChildRouter(menu.children, router)
          // 这里为二级以下，如果还有下级 ，把上级的跳转，指下子集的第一个，同时设置component 为可跳转的嵌套路由
          if (router.children && router.children.length > 0) {
            router.redirect = router.children[0].path // 设置 redirect 跳转
            router.component = Nested // 设置component 为可跳转的嵌套路由
          }
        }
        routerModel.children.push(router)
      } else {
        // 如果是按钮类型的
        setButtonPermission2(menu)
      }
    })
  }
}

/**
 * 查找原始路由,然后组装一下新对象返回
 * @param menu 后台返回的菜单对象
 * @param volatileRoutes 前端定义好的可变路由
 *
 * step two 第三步 在构建子路由的时候需要查找路由
 */
function findOrgRouter(menu, volatileRoutes) {
  // 现根据name去查找
  let router = findOrgRouterByName(menu, volatileRoutes)
  // 如果路由没找到，用path路径找一下试试
  if (!router) {
    router = findOrgRouterByPath(menu, volatileRoutes)
  }
  // 如果还没有找到路由
  if (!router) {
    // 路由为空的情况下，先创建一个
    if (menu && menu.children && menu.children.length > 0) { // 如果这个是上级菜单
      router = new RouterModel(buildPahtUrl(menu.id, menu.path), Layout, new Meta(menu.title, buildIcon(menu.icon)))
    } else {
      router = new RouterModel(buildPahtUrl(menu.id, menu.path), Page404, new Meta(menu.title, buildIcon(menu.icon)))
    }
  } else {
    setButtonPermission(menu, router) // 设置按钮权限
    // 设置path 和路由的对应关系，方便以后可以用path 对应找到路由中的cname
    // pathNameMap.set(menu.path,router.cname) 暂时用不到，浪费内存
  }
  // 是否固定快捷导航栏
  if (menu.affix) {
    router.meta.affix = true
  }
  return router
}

/**
 * step four 第四步 设置页面中的按钮权限
 * @param menu
 * @param router
 */
function setButtonPermission(menu, router) {
  const permMap = new Map()
  if (router.cname) {
    if (menu.permTypes && menu.permTypes.length > 0) {
      menu.permTypes.forEach((perm) => {
        if (perm) {
          permMap.set(perm.code, perm.title)
        }
      })
    }
    buttonPermission.set(router.cname, permMap)
  }
}

/**
 * step four 第四步 第(2)中方式 设置页面中的按钮权限
 * @param menu
 * @param router
 */
function setButtonPermission2(menu) {
  const splitChar = ':'
  let permMap = null
  if (menu.permission && menu.permission.indexOf(splitChar) > 0) {
    const key = menu.permission.split(splitChar)[0]
    // const code = menu.permission.split(splietChar)[1]
    const code = menu.code
    const title = menu.title
    permMap = buttonPermission.get(key)
    if (!permMap) {
      // 如果为空
      permMap = new Map()
      permMap.set(code, title)
    }
    permMap.set(code, title)
    buttonPermission.set(key, permMap)
  }
}

/**
 * 根据后台返回的菜单对象中的name字段 查找原始路由,然后组装一下新对象返回
 * @param menu 后台返回的菜单对象
 * @param volatileRoutes 前端定义好的可变路由
 */
function findOrgRouterByName(menu, volatileRoutes) {
  if (menu && volatileRoutes) {
    let routerModel
    // 外链
    if (menu.isOutside) {
      // 组装的是外链,这儿不需要在构建路由时多构建一个layout
      return buildLinkRouterModel(menu, true)
    }
    for (let i = 0; i < volatileRoutes.length; i++) {
      const router = volatileRoutes[i]
      // 通过后台传过来的name做唯一比对
      if (!menu.code) { // 这是一个空的
        // 如果name为空 ，没必要在找了，直接返回
        return
        // break // 退出for循环
      } else if (menu.code === router.name) { // 找到了前端定义的路由
        //
        routerModel = new RouterModel(buildPahtUrl(menu.id, menu.path), router.component, new Meta(menu.title, buildIcon(menu.icon, router.meta.icon)), router.name)
        // routerModel.name = router.name
        // 快捷导航栏，设置固定标签
        if (router.meta && router.meta.affix) {
          routerModel.meta.affix = true
        }
        break
      } else if (!!router.children && router.children.length > 0) { // 没有找到，但是前端定义的路由对象有下级，到下级中继续寻找
        routerModel = findOrgRouterByName(menu, router.children) // 如果返回的路由不为空，结束递归也结束循环
        if (routerModel) {
          break
        }
      }
    }
    return routerModel
  } else {
    return
  }
}

/**
 * 根据后台返回的菜单对象中的path字段  查找原始路由,然后组装一下新对象返回
 * @param menu 后台返回的菜单对象
 * @param volatileRoutes 前端定义好的可变路由
 */
function findOrgRouterByPath(menu, volatileRoutes) {
  if (!!menu && !!volatileRoutes) {
    let routerModel
    // 外链
    if (menu.isOutside) {
      // 组装的是外链
      return buildLinkRouterModel(menu)
    }
    for (let i = 0; i < volatileRoutes.length; i++) {
      const router = volatileRoutes[i]
      // 如果菜单的path 为空，或者为 #，代表是一起菜单项，有下级路由
      if (!menu.path || menu.path === '#') {
        break
      }
      // 通过后台传过来的path做唯一比对
      if (menu.path === router.path) { // 找到了前端定义的路由
        if (router.redirect) { // 如果path比对上，但在前端的路由定义中却写了redirect，代表有下级路由
          menu.path = router.redirect
          routerModel = findOrgRouterByPath(menu, router.children) // 从该级路由的下级再找详细的组件路由信息
          if (routerModel) { // 如果返回的路由不为空，结束递归也结束循环
            break
          }
        } else { // 找到一个，该路由对象中 如果没有 redirect 属性，代表就是此路由对象
          routerModel = new RouterModel(buildPahtUrl(menu.id, menu.path), router.component, new Meta(menu.title, buildIcon(menu.icon, router.meta.icon)), router.name)
          // routerModel.name = router.name
          // 快捷导航栏，设置固定标签
          if (router.meta && router.meta.affix) {
            routerModel.meta.affix = true
          }
          break
        }
      } else if (router.children && router.children.length > 0) { // 没有找到，但是前端定义的路由对象有下级，到下级中继续寻找
        routerModel = findOrgRouterByPath(menu, router.children) // 如果返回的路由不为空，结束递归也结束循环
        if (routerModel) {
          break
        }
      }
    }
    return routerModel
  } else {
    return
  }
}

/**
 * 构建外部链接的路由
 * @param menu
 * @param notNeedLayOut 不需要上层菜单
 * @returns {RouterModel}
 */
function buildLinkRouterModel(menu, notNeedLayOut) {
  let routerModel
  if (menu.openType === 1 || menu.openType === '1') { // 外链直接打开
    // 组装的是外链
    routerModel = new RouterModel(buildPahtUrl(menu.id, menu.path, 1), Layout, new Meta(menu.title, buildIcon(menu.icon)))
    routerModel.meta.src = menu.path
  } else if (menu.openType === 2 || menu.openType === '2') { // 在嵌入的iframe 中打开
    // 组装的是外链
    const child = new RouterModel(buildPahtUrl(menu.id, menu.path, 2), Iframe, new Meta(menu.title, buildIcon(menu.icon)), menu.id)
    child.meta.src = menu.path
    if (notNeedLayOut) {
      routerModel = child
    } else {
      const children = []
      children.push(child)
      routerModel = {
        path: buildPahtUrl(menu.id),
        component: Layout,
        redirect: child.path,
        children: children
      }
    }
  }
  return routerModel
}
/**
 * 构建路由地址
 * @param id
 * @param path
 * @param openType 1：外链，通过新标签打开  2： 外链，且在嵌入的iframe 中打开
 * @returns {string|*}
 */
function buildPahtUrl(id, path, openType) {
  let result
  if (!path) {
    result = '/' + id
  } else if (path === '/' || path === '#') {
    result = '/'
  } else if (openType && openType === 1) {
    result = path
  } else if (openType && openType === 2) {
    result = '/_fm'
    if (!isExternal(path)) {
      path = endWith(path, '/') ? path.substring(0, path.length - 1) : path
      result = result + (path.startsWith('/') ? path : ('/' + path))
    }
  } else {
    path = endWith(path, '/') ? path.substring(0, path.length - 1) : path
    result = (path.startsWith('/') ? path : ('/' + path))
  }
  // 判断有没有重复的，如果有的话在前面加上id
  if (interiorPath.has(result)) {
    if (isExternal(result)) {
      result = result + '#' // 注意一下，外链的先在后面加#
    } else {
      result = '/' + id + result
    }
  }
  if (result && result.length > 1 && result.endsWith('/')) {
    result = result.substring(0, result.length - 1)
  }
  // 将路由地址放到set 中，只是为了不产生重复的路由地址
  interiorPath.add(result)
  return result
}

/**
 * 构建图标
 * @param icon
 * @returns {string|*}
 */
function buildIcon(icon, orgIcon) {
  return (icon) || (orgIcon) || 'el-icon-document'
}
/**
 *  对外暴露的，更加组件路由名称构建路由工具类的方法
 */
export default buildRouters

/**
 * 清空 原有路由信息
 */
export function clearRouters() {
  interiorPath.clear()
  buttonPermission.clear()
}

export function endWith(str, endStr) {
  const d = str.length - endStr.length
  return (d >= 0 && str.lastIndexOf(endStr) === d)
}
